﻿using System;
using System.Collections.Generic;
using D2D2.SharedInterfaces.Networking;
using D2D2.SharedInterfaces.SharedObject;
using Lidgren.Network;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace D2D2.Core.Sprite
{
    public class Monster : BattleSprite
    {
        private int _currentFrameIndex;
        private float _timeForCurrentFrame;
        private float _frameTime = 0.2f;
        private List<MonsterObject> _snapshots = new List<MonsterObject>();

        private bool _fightAnimation = false;
        private const float FIGHT_FLASH = 0.1f;
        private const float FIGHT_ANIMATION_TIME = 0.4f;
        private float _animationTime = 0;
        private bool _fightVisible = false;
        private const int FIGHT_WIDTH = 48;
        private const int FIGHT_HEIGHT = 27;
        private float _currentFlashTime;

        public Monster(Rectangle location, SpriteType spriteType, MonsterObject monsterObject)
            : base(location, spriteType)
        {

            _texture = _monsterTexture;

            AddSnapshot(monsterObject);
            Id = monsterObject.Id;

            LiveRating = monsterObject.LiveRegen;

            _progress.SetProgress(monsterObject.TotalLive);

        }

        public void AddSnapshot(MonsterObject monster)
        {
            monster.LocalTime = NetTime.Now;
            _snapshots.Add(monster);

            if (_snapshots.Count > 10)
                _snapshots.RemoveAt(0);
        }

        public long Id { get; private set; }

        public override void Update(GameTime gameTime)
        {
            float elapsed = (float) gameTime.ElapsedGameTime.TotalSeconds;

            _timeForCurrentFrame += elapsed;

            if (_timeForCurrentFrame >= _frameTime)
            {
                _currentFrameIndex = (_currentFrameIndex + 1)%(_frames.Count);
                _timeForCurrentFrame = 0.0f;
            }

            if (_snapshots.Count == 0) return;

            MonsterObject monster = GetInerpolatedMonster();

            Alive = monster.CurrentLive > 0;

            _progress.SetProgress(monster.CurrentLive, monster.TotalLive);

            FightAnimationUpdate(elapsed);

        }

        private void FightAnimationUpdate(float elapsed)
        {
            if (_fightAnimation)
            {
                _animationTime += elapsed;
                if (_animationTime > FIGHT_ANIMATION_TIME)
                {
                    _fightAnimation = false;
                    _fightVisible = false;
                    _animationTime = 0;
                    _currentFlashTime = 0;
                }
                else
                {
                    _currentFlashTime += elapsed;
                    if (_currentFlashTime > FIGHT_FLASH)
                    {
                        _currentFlashTime = 0;
                        _fightVisible = !_fightVisible;
                    }
                }
            }
        }

        private MonsterObject GetInerpolatedMonster()
        {
            double shiftTime = NetTime.Now - GlobalConst.INTERPOLATION_SHIFT;

            MonsterObject before = null;
            MonsterObject after = null;
            for (int i = _snapshots.Count - 1; i >= 0; i--)
            {
                if (_snapshots[i].LocalTime < shiftTime)
                {
                    before = _snapshots[i];
                    break;
                }

                if (i == 0)
                {
                    after = _snapshots[i];
                    break;
                }

                if (_snapshots[i].LocalTime >= shiftTime && _snapshots[i - 1].LocalTime <= shiftTime)
                {
                    before = _snapshots[i - 1];
                    after = _snapshots[i];
                    break;
                }
            }

            MonsterObject monster = null;

            if (before == null) monster = after;
            if (after == null) monster = before;

            if (before != null && after != null)
            {
                double weight = (shiftTime - before.LocalTime)/(after.LocalTime - before.LocalTime);
                monster = before.Clone();
                monster.CurrentLive = MathHelper.Lerp(before.CurrentLive, after.CurrentLive, (float) weight);
            }

            return monster;
        }

        public override void Draw(SpriteBatch spriteBatch)
        {
            if (Alive)
            {
                spriteBatch.Draw(_texture, Location, _frames[_currentFrameIndex], Color.White);
                _progress.Draw(spriteBatch);

                if (_fightVisible)
                {
                    Rectangle fightLocation = new Rectangle(Location.X + (Location.Width - FIGHT_WIDTH)/2,
                                                            Location.Y + (Location.Height - FIGHT_HEIGHT)/2, FIGHT_WIDTH,
                                                            FIGHT_HEIGHT);

                    spriteBatch.Draw(_fightTexture, fightLocation, Color.White);
                }
            }
        }

        public override void DecreaseHit()
        {

        }

        protected override int GetFrameCount()
        {
            switch (_spriteType)
            {
                case SpriteType.Blue:
                    return 3;
                case SpriteType.Green:
                    return 4;
                default:
                    throw new Exception("Неизвестный тип монстра.");
            }
        }

        public void MouseClickHandle(int x, int y)
        {

            if (Location.Contains(x, y))
            {
                _fightAnimation = true;

            }
        }
    }
}
